package data;

import java.io.IOException;
import java.util.Calendar;
import java.util.GregorianCalendar;

import network.e2e.FrameReader;
import network.e2e.FrameWriter;
import stalker.Stalker;
import stalker.StalkerParser;
import calendar.CalendarParser;
import data.content.Content;
import data.content.ContentParser;
import data.visitor.DataVisitor;

/**
 * Immutable class that handles a data stored in a room's chat
 */

public class Data {
  
  private Content content_;
  private Stalker creator_;
  private Calendar creation_time_;
  
  private void checkRep() {
    assert (content_ != null &&
            creator_ != null &&
            creation_time_ != null) :
      "Data:fields must not be null";
  }
  
  /**
   * Creates a new data
   * @requires all parameters not null
   * @complexity A(1)
   */
  public Data(Stalker creator, Content content) {
    assert (creator != null && content != null);
    
    creator_ = creator;
    content_ = content;
    creation_time_ = new GregorianCalendar();
    
    checkRep();
  }
  
  /**
   * Reads a data from the net and create it
   * @throws IOException 
   * @requires reader not null
   */
  public Data(FrameReader reader) throws IOException {
    //creator, year, month, day, hour, min, sec, content
    creator_ = StalkerParser.retrieve(reader);
    assert (creator_ != null);
    
    creation_time_ = CalendarParser.retrieve(reader);
    assert (creation_time_ != null);
    
    content_ = ContentParser.retrieve(reader);
    
    checkRep();
  }
  
  /**
   * Sent this through the net
   * @requires writer not null
   * @param writer the net
   */
  public void send(FrameWriter writer) throws IOException {
    assert writer != null;
    StalkerParser.send(creator_, writer);
    CalendarParser.send(creation_time_, writer);
    ContentParser.send(content_, writer);
  }
  
  /**
   * @return the content of this.
   * @complexity A(1)
   */
  public Content getContent() {
    return content_;
  }
  
  /**
   * @return the time of creation of this
   * @complexity A(1)
   */
  public Calendar getCreationCalendar() {
    return creation_time_;
  }
  
  /**
   * @return the creator of this data
   * @complexity A(1)
   */
  public Stalker getCreator() {
    return creator_;
  }
  
  @Override
  public String toString() {
    return this.getContent().toString();
  }
  
  @Override
  public boolean equals(Object obj) {
    if (!(obj instanceof Data)) return false;
    Data that = (Data)obj;
    return this.getContent().equals(that.getContent()) &&
           this.getCreator().equals(that.getCreator()) &&
           this.getCreationCalendar().get(Calendar.YEAR) == that.getCreationCalendar().get(Calendar.YEAR) && 
           this.getCreationCalendar().get(Calendar.MONTH) == that.getCreationCalendar().get(Calendar.MONTH) && 
           this.getCreationCalendar().get(Calendar.DAY_OF_MONTH) == that.getCreationCalendar().get(Calendar.DAY_OF_MONTH) && 
           this.getCreationCalendar().get(Calendar.HOUR_OF_DAY) == that.getCreationCalendar().get(Calendar.HOUR_OF_DAY) && 
           this.getCreationCalendar().get(Calendar.MINUTE) == that.getCreationCalendar().get(Calendar.MINUTE) && 
           this.getCreationCalendar().get(Calendar.SECOND) == that.getCreationCalendar().get(Calendar.SECOND);
  }
  
  public <T> T accept(DataVisitor<T> visitor) {
    return visitor.visit(this);
  }
  
}
